package cn.dduan.fool.design.pattern.great.builder;

/**
 * 建造者模式
 * <p>
 * 优点：
 * 1、建造者模式将复杂产品的创建步骤分解在在不同的方法中，使得创建过程更加清晰，从而更精确控制复杂对象的产生过程
 * 2、通过隔离复杂对象的构建与使用，也就是将产品的创建与产品本身分离开来，使得同样的构建过程可以创建不同的对象
 * 3、并且每个具体建造者都相互独立，因此可以很方便地替换具体建造者或增加新的具体建造者，用户使用不同的具体建造者即可得到不同的产品对象
 * <p>
 * 缺点：
 * 1、但建造者模式的缺陷是要求创建的产品具有较多的共同点、组成部分相似，如果产品之间的差异性很大，则不适合使用建造者模式
 * <p>
 * 抽象工厂模式和建造者模式的区别：
 * 1、抽象工厂模式实现对产品族的创建，建造者模式则更关心的是对象的构建过程
 * 2、在抽象工厂模式中使用“工厂”来描述构建者，而在建造者模式中使用“车间”来描述构建者
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
public class Builder {
    public static void main(String[] args) {
        //服务员
        KFCWaiter waiter = new KFCWaiter();
        //套餐A
        MealA a = new MealA();
        //服务员准备套餐A
        waiter.setMealBuilder(a);
        //获得套餐
        Meal mealA = waiter.construct();

        System.out.print("套餐A的组成部分:");
        System.out.println(mealA.getFood() + " + " + mealA.getDrink());

    }
}

/**
 * 指挥者 Director ｜ KFC的服务员
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class KFCWaiter {
    private MealBuilder mealBuilder;

    /**
     * 准备套餐
     *
     * @param mealBuilder
     * @return void
     * @author dduan
     * @version 1.0
     * @date 2023/4/7
     */
    public void setMealBuilder(MealBuilder mealBuilder) {
        this.mealBuilder = mealBuilder;
    }

    /**
     * 获取套餐
     *
     * @param
     * @return cn.dduan.fool.design.pattern.great.builder.Meal
     * @author dduan
     * @version 1.0
     * @date 2023/4/7
     */
    public Meal construct() {
        //准备食物
        mealBuilder.buildFood();
        //准备饮料
        mealBuilder.buildDrink();

        //准备完毕，返回一个完整的套餐给客户
        return mealBuilder.getMeal();
    }
}

/**
 * 抽象建造者 Builder ｜ 抽象套餐接口
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
abstract class MealBuilder {
    Meal meal = new Meal();

    public abstract void buildFood();

    public abstract void buildDrink();

    public Meal getMeal() {
        return meal;
    }
}

/**
 * 实现抽象套餐接口
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class MealA extends MealBuilder {

    @Override
    public void buildDrink() {
        meal.setDrink("一杯可乐");
    }

    @Override
    public void buildFood() {
        meal.setFood("一盒薯条");
    }
}

/**
 * 实现抽象套餐接口
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class MealB extends MealBuilder {

    @Override
    public void buildDrink() {
        meal.setDrink("一杯柠檬果汁");
    }

    @Override
    public void buildFood() {
        meal.setFood("三个鸡翅");
    }
}

/**
 * 产品类 ｜ 套餐类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class Meal {
    private String food;
    private String drink;

    public String getFood() {
        return food;
    }

    public void setFood(String food) {
        this.food = food;
    }

    public String getDrink() {
        return drink;
    }

    public void setDrink(String drink) {
        this.drink = drink;
    }
}